A Notation for Comonads
نویسندگان
چکیده
The category-theoretic concept of a monad occurs widely as a design pattern for functional programming with effects. The utility and ubiquity of monads is such that some languages provide syntactic sugar for this pattern, further encouraging its use. We argue that comonads, the dual of monads, similarly provide a useful design pattern, capturing notions of context dependence. However, comonads remain relatively under-used compared to monads—due to a lack of knowledge of the design pattern along with the lack of accompanying simplifying syntax. We propose a lightweight syntax for comonads in Haskell, analogous to the do-notation for monads, and provide examples of its use. Via our notation, we also provide a tutorial on programming with comonads. Many algebraic approaches to programming apply concepts from category theory as design patterns for abstracting and structuring programs. For example, the category-theoretic notion of a monad is widely used to structure programs with side effects, encapsulating effects within a parametric data type [1, 2]. A monadic data type M has accompanying operations which provide composition of functions with structured output of type a → M b. Side effects can be seen as impure output behaviour, encoded by the data type M . Monads are so effective as an abstraction technique that some languages provide a lightweight syntactic sugar simplifying programming with monads, such as the do-notation in Haskell and the let! notation in F# [3]. Comonads are the dual structure to monads, where a comonadic data type C has operations for the composition of functions with structured input, of type C a → b. Whilst monads capture impure output behaviour (side effects), comonads capture impure input behaviour, often described as context dependence, encoded by the data type C. There are various examples of programming with comonads in the literature including dataflow programming via streams [4], attribute evaluation [5], array computations [6], and more [7]. However, despite these examples, comonads are less widely used than monads. There are two reasons for this: one is that they are less well-known, the other, related reason is the lack of language support, which impedes the use of comonads as a design pattern. To remedy this, we propose a syntax which simplifies programming with comonads in Haskell, called the codo-notation, which also serves to promote the comonad design pattern. In Haskell, comonads are defined by the following class: 1 Available via Edward Kmett’s Control.Comonad package. class Comonad c where extract :: c a → a extend :: (c a → b) → c a → c b The contextual view of comonads is that values of type c a encode contextdependent computations of values of type a, and functions c a → b describe local operations within some context. The extract operation defines a notion of current context and is a trivial local operation returning the value at this context; extend defines the range of all possible contexts, extending a local operation to a global operation by applying it at every context. Thus comonads abstract “boilerplate” code for extending an operation, defined at one context, to all contexts. For example, arrays can be seen as encoding contextual computations, where a value depends on its position. An array paired with an array index denoting the current context – called the cursor – is a comonad. Its extract operation accesses the cursor element of the array; extend applies a local operation, which computes a value from an array at a particular cursor, to an array at each possible cursor index in its domain (i.e., globally), computing an array of results [6]. Local operations of this form, on arrays, are ubiquitous in image processing, scientific computing, and cellular automata. The codo-notation simplifies programming with comonads. For example, the following codo-block defines a local operation for computing image contours: contours :: CArray (Int , Int) Float → Float contours = codo x ⇒ y ← gauss2D x z ← gauss2D y w ← (extract y)− (extract z ) laplace2D w where CArray i a is a cursored-array data type, with index type i and element type a, and gauss2D , laplace2D :: CArray (Int , Int) Float → Float compute, at a particular index, discrete Gaussian and Laplace operators on 2D arrays. A contour image can thus be computed by applying (extend contours) to an image. The primary contribution of this paper is the codo-notation, introduced in detail in Section 1, continuing with arrays as an example. The notation desugars into the operations of a comonad (Section 3) which provides an equational theory for the notation following from the laws of a comonad (Section 2). The codo-notation is analogous to the do-notation for programming with monads in Haskell, but with some notable differences which are explained from a categorical semantics perspective in Section 4. Section 5 discusses related work, including a comparison of the codo-notation to Haskell’s arrow notation. This paper contributes examples (arrays, trees, and graphs), explanation, and notation to promote comonads in programming. A prototype of the notation, as a macro-based library using quasi-quoting brackets, is provided by the codo-notation package. An implementation as a GHC extension is in progress. 2 http://hackage.haskell.org/package/codo-notation Array example The array comonad is used throughout the next section to introduce codo. It is defined in Haskell by the following data type and instance: data CArray i a = CA (Array i a) i instance Ix i ⇒ Comonad (CArray i) where extract (CA a i) = a ! i extend f (CA a i) = let es ′ = map (λj → (j , f (CA a j ))) (indices a) in CA (array (bounds a) es ) i where extract accesses the cursor element using the array indexing operation !, and, for every index j of the parameter array, extend applies f to the array with j as its cursor, returning an index-value pair list from which the result array is constructed. Note, the return and parameter arrays have the same size and cursor, i.e., extend preserves the incoming context in its result. Many array operations can be defined as local operations c a → b (hereafter comonadic operations, sometimes called coKleisli arrows/morphisms in the literature) using relative indexing, e.g., the laplace2D operator, for approximating differentiation, can be defined: laplace2D :: CArray (Int , Int) Float → Float laplace2D a = a ? (−1, 0) + a ? (1, 0) + a ? (0,−1) + a ? (0, 1)− 4 ∗ a ? (0, 0) where (?) abstracts relative indexing with bounds checking and default values: (?) :: (Ix i ,Num a,Num i) ⇒ CArray i a → i → a (CA a i) ? i ′ = if (inRange (bounds a) (i + i )) then a ! (i + i ) else 0 (where Ix is the class of valid array-index types). Whilst laplace2D computes the Laplacian at a single context (locally), extend laplace2D computes the Laplacian at every context (globally), returning an array rather than a single float.
منابع مشابه
Linear Exponential Comonads without Symmetry
The notion of linear exponential comonads on symmetric monoidal categories has been used for modelling the exponential modality of linear logic. In this paper we introduce linear exponential comonads on general (possibly non-symmetric) monoidal categories, and show some basic results on them.
متن کاملCoherence for monoidal monads and comonads
The goal of this paper is to prove coherence results with respect to relational graphs for monoidal monads and comonads, i.e. monads and comonads in a monoidal category such that the endofunctor of the monad or comonad is a monoidal functor (this means that it preserves the monoidal structure up to a natural transformation that need not be an isomorphism). These results are proved first in the ...
متن کاملTowards Merging Recursion and Comonads
Comonads are mathematical structures that account naturally for eeects that derive from the context in which a program is executed. This paper reports ongoing work on the interaction between recursion and comonads. Two applications are shown that naturally lead to versions of a comonadic fold operator on the product comonad. Both versions capture functions that require extra arguments for their...
متن کاملRecursive coalgebras from comonads
We discuss Osius’s [22] concept of a recursive coalgebra of a functor from the perspective of programming semantics and give some new sufficient conditions for the recursiveness of a functor-coalgebra that are based on comonads, comonad-coalgebras and distributive laws.
متن کاملProgramming contextual computations
Modern computer programs are executed in a variety of different contexts: on servers, handheld devices, graphics cards, and across distributed environments, to name a few. Understanding a program’s contextual requirements is therefore vital for its correct execution. This dissertation studies contextual computations, ranging from application-level notions of context to lowerlevel notions of con...
متن کاملذخیره در منابع من
با ذخیره ی این منبع در منابع من، دسترسی به آن را برای استفاده های بعدی آسان تر کنید
عنوان ژورنال:
دوره شماره
صفحات -
تاریخ انتشار 2012